package cn.stylefeng.roses.kernel.auth.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import cn.stylefeng.roses.kernel.apiauth.api.constants.ApiAuthConstants;
import cn.stylefeng.roses.kernel.auth.exception.ApiClientExceptionEnum;
import cn.stylefeng.roses.kernel.auth.pojo.AuthTokenRequest;
import cn.stylefeng.roses.kernel.auth.pojo.AuthTokenResponse;
import cn.stylefeng.roses.kernel.jwt.JwtTokenOperator;
import cn.stylefeng.roses.kernel.jwt.api.pojo.config.JwtConfig;
import cn.stylefeng.roses.kernel.manage.entity.ApiClient;
import cn.stylefeng.roses.kernel.manage.service.ApiClientService;
import cn.stylefeng.roses.kernel.rule.enums.StatusEnum;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;

/**
 * 创建api认证的token
 *
 * @author fengshuonan
 * @since 2023/10/25 22:21
 */
@Service
public class AuthTokenService {

    @Resource
    private ApiClientService apiClientService;

    /**
     * 获取认证token
     *
     * @author fengshuonan
     * @since 2023/10/25 22:25
     */
    public AuthTokenResponse generateAuthToken(AuthTokenRequest authTokenRequest) {

        // 1. 时间戳转化为日期格式
        String timestamp = authTokenRequest.getTimestamp();
        DateTime requestDateTime = null;
        try {
            requestDateTime = DateUtil.parse(timestamp);
        } catch (Exception e) {
            throw new ServiceException(ApiClientExceptionEnum.TIMESTAMP_ERROR);
        }

        // 2. 判断时间是否过期，过期则直接认证失败，2分钟时间过期
        DateTime expiredDateTime = requestDateTime.offset(DateField.MINUTE, 2);
        if (expiredDateTime.isBefore(new Date())) {
            throw new ServiceException(ApiClientExceptionEnum.API_CLIENT_AUTH_EXPIRED);
        }

        // 3. 根据api客户端编码，查询到这个api客户端信息
        String apiClientCode = authTokenRequest.getApiClientCode();
        ApiClient apiClient = apiClientService.getByCode(apiClientCode);

        // 3.1 校验客户端是否被禁用
        if (!apiClient.getApiClientStatus().equals(StatusEnum.ENABLE.getCode())) {
            throw new ServiceException(ApiClientExceptionEnum.API_CLIENT_DISABLED);
        }

        // 4. 获取md5加密的字符串（客户端秘钥+时间戳）
        String secretWithTimestampMd5 = authTokenRequest.getApiClientSecretEncode();

        // 5. 将客户端本身的秘钥和时间戳加密得出正确的md5值，并进行比对
        String rightMd5 = SecureUtil.md5(apiClient.getApiClientSecret() + authTokenRequest.getTimestamp());
        if (!rightMd5.equals(secretWithTimestampMd5)) {
            throw new ServiceException(ApiClientExceptionEnum.API_CLIENT_LOGIN_SECRET_ERROR);
        }

        // 6. 如果校验通过，颁发Token
        AuthTokenResponse authTokenResponse = new AuthTokenResponse();

        // 获取jwt秘钥信息和token过期时间
        JwtConfig jwtConfig = new JwtConfig();
        jwtConfig.setJwtSecret(apiClient.getApiClientSecret());
        jwtConfig.setExpiredSeconds(Convert.toLong(apiClient.getApiClientTokenExpiration()));
        JwtTokenOperator jwtTokenOperator = new JwtTokenOperator(jwtConfig);

        // 组装payload
        HashMap<String, Object> payload = new HashMap<>();
        payload.put(ApiAuthConstants.API_AUTH_PAYLOAD_CLIENT_ID_FIELD_NAME, apiClient.getApiClientId());

        // 生成token
        String token = jwtTokenOperator.generateToken(payload);
        authTokenResponse.setToken(token);

        return authTokenResponse;
    }

}
